package grapher;

/*
 * EGraphImpl.java
 * Author: Ben McCormick
 * Written: June 27 2011
 * Last Edited: June 27 2011
 * Ben McCormick 2011
 * This file is part of The Eikona Project .
 *    Copyright 2011 Ben McCormick
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *    
 *    http://www.apache.org/licenses/LICENSE-2.0
 *    
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 */

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;

import calculator.EikonaCalculator;
import calculator.EquationEvaluator;
import exceptions.InvalidExpressionException;


/**
 * Implementation of the Eikona Grapher interface.  Produces graphs for the Eikona calculator project
 * 
 */
public class EGraphImpl implements EikonaGrapher {

	private BigDecimal xmin,ymin,xmax,ymax;
	private EikonaCalculator calc = new EquationEvaluator();
	private final int NUMPOINTS = 200;
	private final int GRAPHWIDTH = 400;
	private final int GRAPHHEIGHT = 400;
	private final int DOTSIZE = 4;
	private final Color BGCOLOR = new Color(237,233,208);
	private final Color AXISCOLOR = new Color(206,192,195);
	public static long file_index=0;
	private Color[] colors ={Color.BLUE,Color.RED,Color.GREEN,Color.YELLOW,Color.CYAN};
	private int colorindex =0;
	public EGraphImpl()
	{
		xmin = new BigDecimal(-10);
		ymin = new BigDecimal(-10);
		xmax = new BigDecimal(10);
		ymax = new BigDecimal(10);
	}
	

	@Override
	public File graph(String[] expressions) {
		BigDecimal point;
		int index =0;
		BufferedImage graph =createNewGraph();
		for(String equation: expressions)
		{
			BigDecimal[][] points = new BigDecimal[NUMPOINTS][2];
			
			point =xmin;
			while(index < NUMPOINTS)
			{	
			calc.addVariable("x",point);
			try {
				BigDecimal yval = calc.compute(equation);
				points[index][0] = point;
				points[index][1] = yval;
			} catch (NumberFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidExpressionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			index ++;
			
			point = point.add((xmax.subtract(xmin)).divide(new BigDecimal(NUMPOINTS)));
			}
			addPointsToGraph(points,graph);
			index=0;
		}

		File outputfile = new File("graph_"+file_index+".png");
		file_index++;
	    try {
			ImageIO.write(graph, "png", outputfile);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return outputfile;
		
	}
	
	/**
	 * Given an array of points draw them on the graph
	 * @param points
	 * @param graph
	 */
	private void addPointsToGraph(BigDecimal[][] points,BufferedImage graph) {
		Graphics2D draw = graph.createGraphics();
		
		//set the line to the current color and update the color setting
		draw.setColor(colors[colorindex]);
		colorindex++;
		if(colorindex>=colors.length)
		{
			colorindex=0;
		}
		
		
		for(int i=0; i<NUMPOINTS-1; i++)
		{
			int y1 = (int)convertPoint(points[i][1]);
			int y2 = (int)convertPoint(points[i+1][1]);
			
			if(y1>0 && y1<GRAPHHEIGHT && y2>0 && y2<GRAPHHEIGHT)
			{
			draw.drawLine(i*GRAPHWIDTH/NUMPOINTS, y1, (i+1)*GRAPHWIDTH/NUMPOINTS, y2);
			
			}
		}
		
	}
	/**
	 * Converts the graph coordinates to drawing coordinates
	 * @param x
	 * @return
	 */
	private float convertPoint(BigDecimal x)
	{
		//if its null return 1, which will be off the charts
		if(x==null)
		{
			return -1;
		}
		BigDecimal a = (new BigDecimal(GRAPHHEIGHT)).divide(ymin.subtract(ymax));
		BigDecimal b = (new BigDecimal(GRAPHHEIGHT).multiply(ymax).multiply(new BigDecimal(-1))
				).divide(ymin.subtract(ymax));
		float y = ((x.multiply(a)).add(b)).floatValue();
		
		return y;
	}

	/**
	 * Generates a new graph
	 * @return
	 */
	private BufferedImage createNewGraph() {
		BufferedImage graph = new BufferedImage(GRAPHWIDTH,GRAPHHEIGHT,BufferedImage.TYPE_INT_RGB);
		Graphics2D draw = graph.createGraphics();
		
		draw.setColor(BGCOLOR);
		draw.fillRect(0, 0, GRAPHWIDTH, GRAPHHEIGHT);
		draw.setColor(AXISCOLOR);
		draw.drawLine(GRAPHWIDTH/2,0,GRAPHWIDTH/2, GRAPHHEIGHT);
		draw.drawLine(0, GRAPHHEIGHT/2, GRAPHWIDTH, GRAPHHEIGHT/2);
		return graph;
	}


	@Override
	public boolean setWindow(BigDecimal _xmin, BigDecimal _xmax, BigDecimal _ymin, BigDecimal _ymax) {
		if(_xmax.floatValue() > _xmin.floatValue() && _ymax.floatValue() > _ymin.floatValue())
		{
		return false;
		}
		
		xmin=_xmin;
		ymin=_ymin;
		xmax=_xmax;
		ymax=_ymax;
		return true;
	}


	@Override
	public BigDecimal getXMax() {
		return xmax;
	}


	@Override
	public BigDecimal getXMin() {
		return xmin;
	}


	@Override
	public BigDecimal getYMax() {
		return ymax;
	}


	@Override
	public BigDecimal getYMin() {
		return ymin;
	}
	
	public static void main(String[] args)
	{
		String[] test = {"x^3","x+2"};
		EGraphImpl gr = new EGraphImpl();
		gr.graph(test);
	}
	

}
